Skip to content

feat: smart PCH rebuild, #include/import completion, rapid-edit robustness - #394

Merged
16bit-ykiko merged 20 commits into
mainfrom
feat/smart-pch-rebuild
Apr 6, 2026
Merged

feat: smart PCH rebuild, #include/import completion, rapid-edit robustness#394
16bit-ykiko merged 20 commits into
mainfrom
feat/smart-pch-rebuild

Conversation

@16bit-ykiko

@16bit-ykiko 16bit-ykiko commented Apr 5, 2026

Copy link
Copy Markdown
Member

Summary

Preamble completeness check

  • is_preamble_complete() in scan.cpp: checks whether #include/import/export module directives in the preamble region are syntactically complete (have closing >/"/;)
  • ensure_pch defers PCH rebuild when preamble is incomplete (user still typing), reuses old PCH instead of failing

#include / import completion

  • Master intercepts completion requests in #include "..." / #include <...> / import ... contexts before forwarding to worker
  • complete_include(): searches include paths (from compile args via SearchConfig) using DirListingCache, supports quoted/angled/multi-level paths
  • complete_import(): filters path_to_module map by prefix
  • Word boundary checks prevent false matches (e.g. important not treated as import)

Detached compile task (rapid-edit fix)

  • Compile operations (ensure_deps + send_stateful + publish_diagnostics) run as detached tasks via loop.schedule(), independent of the LSP request coroutine chain
  • LSP $/cancelRequest can no longer kill in-flight compilations — previously, cancellation would destroy the ensure_compiled coroutine frame, leaving doc.compiling permanently set and hanging all subsequent requests
  • CompileGuard RAII ensures doc.compiling is always cleaned up even if the detached task fails
  • Stale feature requests (where ast_dirty became true after compile finished) are dropped before forwarding to worker

Other fixes

  • signal(SIGPIPE, SIG_IGN) on POSIX: prevents server crash when LSP client disconnects mid-write
  • CompilationUnitRef::file_path() / deps(): null-check FileEntryRef to prevent segfault on invalid FileID
  • stateless_worker.cpp: log BuildPCH diagnostic errors for debuggability
  • Default worker counts changed to 2 stateful + 3 stateless
  • logging_dir default changed to .clice/logs in config

Tests

  • 19 unit tests for is_preamble_complete (incomplete #include, import, export module, mixed cases)
  • Integration tests: test_include_completion.py (5 tests), test_import_completion.py (4 tests), test_rapid_edit.py (2 tests), test_pch.py (4 new tests)
  • Smoke test: rapid_edit.jsonl — recorded VSCode session with 40 rapid edits + 61 cancel requests

Test plan

  • Unit tests: 463 passed
  • Integration tests: 104 passed
  • Smoke test (rapid_edit.jsonl): PASS
  • Manual VSCode testing with #include <iostream> project

🤖 Generated with Claude Code

When the user is mid-edit in the preamble region (e.g. typing an
#include path that isn't closed yet), skip the PCH rebuild and reuse
the existing PCH. This avoids wasteful builds with incomplete code.

- Add is_preamble_complete() that checks all #include/#import directives
  have properly closed "" or <> delimiters
- In ensure_pch, when preamble hash changed but content is incomplete,
  defer rebuild and keep using the old PCH

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Apr 5, 2026

Copy link
Copy Markdown

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds preamble-completeness detection, master-level include/import completion, and PCM-build triggering from scanned in-memory buffers; updates master server logic to prefer cached PCH when preamble is incomplete and to handle include/import completions locally.

Changes

Cohort / File(s) Summary
Master server logic
src/server/master_server.cpp, src/server/master_server.h
Adds preamble-aware PCH reuse; scans in-memory buffer for module imports and triggers PCM compilation via compile_graph/path_to_module; adds completion types and APIs plus master-side include/import completion handlers and detection.
Preamble scanning API
src/syntax/scan.cpp, src/syntax/scan.h
Adds clice::is_preamble_complete(content, bound) to detect incomplete #include/import/export preamble lines (unclosed quotes/angles or missing ;).
Tests — include completion workspace
tests/conftest.py, tests/data/include_completion/main.cpp, tests/data/include_completion/myheader.h, tests/data/include_completion/subdir/nested.h
Adds test workspace files and compile_commands.json fixture support for include-completion tests.
Tests — include completion integration/unit
tests/integration/test_include_completion.py, tests/unit/syntax/scan_tests.cpp
Adds integration tests exercising quoted/angled include completions and negative cases; unit tests for is_preamble_complete covering include/module completeness scenarios.

Sequence Diagram(s)

mermaid
sequenceDiagram
autonumber
participant Client as Client
participant Master as MasterServer
participant FS as FileSystem
participant Worker as StatelessWorker
Client->>Master: textDocument/completion(request, doc, pos)
Master->>Master: detect_completion_context(text, offset)
alt on #include or import preamble
Master->>FS: list headers / lookup modules (path pool)
FS-->>Master: path entries / module info
Master->>Client: completion items (include/import results)
else otherwise
Master->>Worker: forward completion request
Worker-->>Master: completion results
Master-->>Client: completion results
end

mermaid
sequenceDiagram
autonumber
participant Master as MasterServer
participant InMem as InMemoryBuffer
participant PathPool as path_to_module
participant CG as CompileGraph
Master->>InMem: scan(text) for module imports
InMem-->>Master: list of module names
loop per missing module
Master->>PathPool: resolve module -> unit path
alt unit known & PCM missing
Master->>CG: request build PCM for unit
CG-->>Master: build scheduled/complete
else unknown
Master-->>Master: log unknown module
end
end

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

"A rabbit hops through preamble light,
Fetching paths and modules bright.
When includes are half-said, I keep old PCH tight—
I nibble tests and stitch completion night.
🐇✨"

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the three main objectives: smart PCH rebuild (defer when preamble incomplete), #include/import completion (master-level handling), and module dependency scanning (buffer-aware). It is concise, specific, and directly reflects the changeset's primary features.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/smart-pch-rebuild

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/syntax/scan.cpp (1)

483-491: CRLF line endings may cause false positives.

The split('\n') approach doesn't strip \r from Windows-style line endings. If a user types #include\r\n (incomplete directive with CRLF), after_keyword would be "\r" instead of empty, causing the check at line 518 to incorrectly treat it as complete (macro case).

Consider trimming the line on both sides or explicitly handling \r:

🔧 Suggested fix
     while(!preamble.empty()) {
         auto [line, rest] = preamble.split('\n');
         preamble = rest;

-        auto trimmed = line.ltrim();
+        auto trimmed = line.ltrim().rtrim("\r");

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: c451e53e-bd0b-403a-b59f-39a68c35ac6c

📥 Commits

Reviewing files that changed from the base of the PR and between b6886d2 and ebdeb59.

📒 Files selected for processing (3)
  • src/server/master_server.cpp
  • src/syntax/scan.cpp
  • src/syntax/scan.h

16bit-ykiko and others added 3 commits April 5, 2026 19:15
Also defer PCH/PCM rebuild when the user is typing incomplete module
statements like `import std` (missing `;`) or `export module `
(incomplete module name).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Include/import completion:
- Intercept completion requests in master when cursor is on #include or
  import line, handle directly without forwarding to stateless worker
- #include completion: enumerate headers from SearchConfig + DirListingCache,
  support subdirectory navigation (e.g. "sys/ty" prefix)
- import completion: filter path_to_module by prefix, insert with ";"

Buffer-aware module dependencies:
- In ensure_deps, scan buffer text for import statements to discover
  module dependencies not yet known to compile_graph (user added import
  without saving)
- Build needed PCMs on-the-fly before compilation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- detect_completion_context: return early after # branch so #import
  (Objective-C) doesn't fall through to C++20 import detection
- is_preamble_complete: add word boundary check so "important" etc.
  don't match "import"/"export" keywords

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@16bit-ykiko 16bit-ykiko changed the title feat: defer PCH rebuild when preamble is incomplete feat: smart PCH rebuild, #include/import completion, buffer-aware module deps Apr 5, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/server/master_server.cpp`:
- Around line 683-709: The current use of scan(text) is ineffective because
scan() doesn't populate scan_result.modules (it only extracts includes/module
declarations), so the loop over scan_result.modules is a no-op; fix by either
replacing the call to scan(text) with scan_precise(text, args) (using the same
compiler arguments used elsewhere and wiring through the required preprocess
step so PreciseScanPPCallbacks::moduleImport() fills modules) or by extending
scan() to recognize and record import directives into its result; update the
code around scan_result.modules, keep the existing behavior of attempting to
build missing PCMs (pcm_paths, compile_graph->compile_deps(pid)), and ensure the
new call provides/accepts the necessary compiler arguments used by scan_precise
so imported modules are discovered at runtime.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: da4f9542-e95a-4816-91a1-b1ec82f7aaef

📥 Commits

Reviewing files that changed from the base of the PR and between ffd7016 and 17e7c91.

📒 Files selected for processing (2)
  • src/server/master_server.cpp
  • src/server/master_server.h

Comment thread src/server/master_server.cpp

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
src/server/master_server.cpp (1)

683-709: ⚠️ Potential issue | 🟠 Major

scan(text) does not populate modules — this code path is ineffective.

As noted in a previous review, the lexer-based scan() function only extracts #include directives and module declarations (module_name, is_interface_unit). It does not handle import statements — those are only captured by scan_precise() through its PreciseScanPPCallbacks::moduleImport() callback.

The ScanResult::modules vector (see src/syntax/scan.h:50) is only populated by scan_precise(), not by scan(). Therefore, scan_result.modules will always be empty here, making the entire iteration block unreachable dead code.

To discover import statements from the in-memory buffer, either:

  1. Use scan_precise() (requires compilation arguments, more expensive)
  2. Extend scan() to extract cxx_import_decl / cxx_export_import_decl directives

,

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/server/master_server.cpp` around lines 683 - 709, The current buffer-scan
uses scan(text) but ScanResult::modules is only filled by scan_precise(), so the
loop is dead; fix by either (A) switching this path to call scan_precise(...)
with the appropriate compilation arguments and then use the returned
ScanResult.modules (leveraging PreciseScanPPCallbacks::moduleImport), or (B)
extend the lightweight scan(...) implementation to also recognize C++20
import/export import directives (cxx_import_decl / cxx_export_import_decl) and
populate ScanResult::modules so the existing logic (checking path_to_module,
pcm_paths, compile_graph->compile_deps(pid)) works; update references in this
block to use the chosen function (scan_precise or the enhanced scan) and ensure
ScanResult::modules is actually filled before iterating.
🧹 Nitpick comments (1)
src/syntax/scan.cpp (1)

479-491: Missing word-boundary check for #include/#import directive keywords.

The function checks directive.starts_with("include") or directive.starts_with("import") without verifying a word boundary, meaning a hypothetical directive like #includefoo would be incorrectly treated as an include directive. While this is an unlikely edge case in practice, it's inconsistent with the word-boundary check applied for C++20 import/export keywords in is_preamble_complete (lines 521-524).

Also, the keyword length calculation at line 482/489 assumes "import" (6 chars) or "include" (7 chars), but #import in Objective-C uses 6 chars. If a #include_next directive were passed here, the offset would be wrong.

🔧 Suggested improvement for robustness
 static bool is_include_directive_complete(llvm::StringRef directive) {
+    // Determine keyword and its length
+    llvm::StringRef keyword;
+    if(directive.starts_with("include_next") && 
+       (directive.size() == 12 || !llvm::isAlnum(directive[12]))) {
+        keyword = "include_next";
+    } else if(directive.starts_with("include") && 
+              (directive.size() == 7 || !llvm::isAlnum(directive[7]))) {
+        keyword = "include";
+    } else if(directive.starts_with("import") && 
+              (directive.size() == 6 || !llvm::isAlnum(directive[6]))) {
+        keyword = "import";
+    } else {
+        return true;  // Not a recognized include/import directive
+    }
+
     if(directive.contains('"')) {
-        auto after_keyword = directive.drop_front(directive.starts_with("import") ? 6 : 7);
+        auto after_keyword = directive.drop_front(keyword.size());
         return after_keyword.count('"') >= 2;
     }
     if(directive.contains('<')) {
         return directive.contains('>');
     }
     // No " or < — might be a macro (`#include` FOO) or just incomplete (`#include` ).
-    auto after_keyword = directive.drop_front(directive.starts_with("import") ? 6 : 7).ltrim();
+    auto after_keyword = directive.drop_front(keyword.size()).ltrim();
     return !after_keyword.empty();
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/syntax/scan.cpp` around lines 479 - 491, is_include_directive_complete
currently uses directive.starts_with("import")/("include") without ensuring a
word boundary and then hardcodes lengths 6/7; update
is_include_directive_complete to first detect which keyword actually matches
("import" vs "include") and verify a word boundary by checking the character
after the keyword is end-of-string, whitespace, '"' or '<' (so "#include_next"
won't be treated as "include"); compute the keyword length from that matched
keyword and use it when computing after_keyword (instead of always using 6/7) so
Objective-C "#import" and other edge cases are handled correctly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/server/master_server.cpp`:
- Around line 1152-1200: detect_completion_context incorrectly treats
identifiers like "important" as the import keyword because it uses
import_check.consume_front("import") without a word-boundary check; update the
logic in detect_completion_context so you only accept "import" when the next
character (if any) is not an alphanumeric (use llvm::isAlnum or equivalent)
before consuming/returning and keep returning {CompletionContext::Import,
import_check.str()} when matched; additionally, handle Objective‑C "#import" in
the preprocessor branch (the block that currently checks
directive.consume_front("include")) so that if directive.consume_front("import")
succeeds you treat it like an include directive (return the appropriate
IncludeQuoted or IncludeAngled context based on the following quote/angle)
instead of falling through.

---

Duplicate comments:
In `@src/server/master_server.cpp`:
- Around line 683-709: The current buffer-scan uses scan(text) but
ScanResult::modules is only filled by scan_precise(), so the loop is dead; fix
by either (A) switching this path to call scan_precise(...) with the appropriate
compilation arguments and then use the returned ScanResult.modules (leveraging
PreciseScanPPCallbacks::moduleImport), or (B) extend the lightweight scan(...)
implementation to also recognize C++20 import/export import directives
(cxx_import_decl / cxx_export_import_decl) and populate ScanResult::modules so
the existing logic (checking path_to_module, pcm_paths,
compile_graph->compile_deps(pid)) works; update references in this block to use
the chosen function (scan_precise or the enhanced scan) and ensure
ScanResult::modules is actually filled before iterating.

---

Nitpick comments:
In `@src/syntax/scan.cpp`:
- Around line 479-491: is_include_directive_complete currently uses
directive.starts_with("import")/("include") without ensuring a word boundary and
then hardcodes lengths 6/7; update is_include_directive_complete to first detect
which keyword actually matches ("import" vs "include") and verify a word
boundary by checking the character after the keyword is end-of-string,
whitespace, '"' or '<' (so "#include_next" won't be treated as "include");
compute the keyword length from that matched keyword and use it when computing
after_keyword (instead of always using 6/7) so Objective-C "#import" and other
edge cases are handled correctly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 8eb8bca2-f6f6-4d74-93a5-79190525bc8b

📥 Commits

Reviewing files that changed from the base of the PR and between 17e7c91 and d78b54a.

📒 Files selected for processing (2)
  • src/server/master_server.cpp
  • src/syntax/scan.cpp

Comment thread src/server/master_server.cpp
…egration tests

Unit tests (19 cases):
- #include completeness: quoted, angled, macro, empty, multiple
- C++20 module: import, export module, export import with/without ;
- Edge cases: empty preamble, word boundary (important != import), mixed

Integration tests (5 cases):
- Quoted include completion with prefix filtering
- Subdirectory include completion (subdir/nested.h)
- Angled include completion for system headers
- No include completion on regular code
- Empty prefix lists all local headers

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@tests/integration/test_include_completion.py`:
- Around line 130-135: The test currently skips validation when result is None;
add an explicit assertion that result is not None before extracting items/labels
so the negative-path test fails if completion is completely broken.
Specifically, in tests/integration/test_include_completion.py around the block
using the result variable, insert an assert result is not None (or use assert
result) prior to computing items = result.items if hasattr(result, "items") else
result and the subsequent labels checks to ensure the test always validates the
expected non-include completions.
- Around line 161-164: The test's assertion list doesn't match the comment: when
prefix is empty the completion should include both "myheader.h" and the
directory entry "subdir/"; update the assertions in
tests/integration/test_include_completion.py to also assert that "subdir/" is
present in the labels variable (in addition to the existing assert "myheader.h"
in labels) so the test verifies both file and directory entries are returned.

In `@tests/unit/syntax/scan_tests.cpp`:
- Around line 414-418: The test MixedIncludeAndImportAllComplete currently uses
compute_preamble_bound(content) which returns a bound that stops before the
"import std;" line so the import isn't being validated; change the test to set
the bound to cover the import (for example use size_t bound = content.size() or
otherwise compute a bound that includes the "import std;" token) before calling
is_preamble_complete(content, bound) so both the `#include` and import are
checked.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 1e7c080b-b7c2-4bc7-8541-de111be66ef1

📥 Commits

Reviewing files that changed from the base of the PR and between d78b54a and 0c76b3e.

📒 Files selected for processing (6)
  • tests/conftest.py
  • tests/data/include_completion/main.cpp
  • tests/data/include_completion/myheader.h
  • tests/data/include_completion/subdir/nested.h
  • tests/integration/test_include_completion.py
  • tests/unit/syntax/scan_tests.cpp
✅ Files skipped from review due to trivial changes (3)
  • tests/data/include_completion/subdir/nested.h
  • tests/data/include_completion/myheader.h
  • tests/conftest.py

Comment thread tests/integration/test_include_completion.py Outdated
Comment thread tests/integration/test_include_completion.py
Comment thread tests/unit/syntax/scan_tests.cpp
16bit-ykiko and others added 15 commits April 5, 2026 21:06
…tests

4 integration test cases:
- Import completion basic: type "import " → lists known module "A"
- Import completion with prefix: "import A" → filters to module A
- Import completion dotted names: "import my." → shows my.app, my.io
- Buffer-aware module deps: add import in buffer without saving,
  verify PCM is built and compilation succeeds

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
getFileEntryRefForID can return an invalid entry for certain FileIDs
(e.g. built-in buffers, remapped files). The old code had an assert
that was optimized out in RelWithDebInfo, leading to a null deref in
FileEntryRef::getName(). Return empty string for invalid entries and
skip them in deps collection.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Default worker counts: 3 stateless, 2 stateful (was cpu/4 each)
- drain_stderr demoted to LOG_DEBUG — workers have their own log files,
  master.log no longer contains duplicated worker output. drain_stderr
  still captures crash/assertion output at debug level.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- test_preamble_edit_then_hover: edit preamble (add #include), verify
  AST still works after PCH rebuild
- test_preamble_edit_multiple_times: 3 consecutive preamble edits,
  verify no errors accumulate

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add DEBUG logging to forward_stateful, forward_stateless, and
  ensure_compiled with path, version, generation, ast_dirty state
- Add didChange debug log with version and generation
- Log early-exit reasons (ensure_compiled failed, worker error, etc.)
- Add test_preamble_edit_then_hover and test_preamble_edit_multiple_times

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Ignore SIGPIPE at startup so writing to closed pipes returns EPIPE
  instead of killing the process (macOS CI crash)
- Change test_preamble_edit_then_hover to add a comment instead of
  #include <cstdio> — avoids slow system header PCH build in CI

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove std::signal(SIGPIPE, SIG_IGN) from main — not appropriate
- Restore #include <cstdio> in test_preamble_edit_then_hover
- Fix clang-format on logging arguments in master_server.cpp

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Root cause: when multiple ensure_compiled() coroutines waited on
doc.compiling->wait() and the in-flight compile finished with a
generation mismatch, ALL waiters woke up simultaneously. Each one
saw ast_dirty=true and fell through to start its OWN compile request,
flooding the stateful worker and causing IPC deadlock.

Fix: change the compiling wait from `if` to `while` loop — after
waking, re-check doc.compiling before starting a new compile. Only
the first waiter starts a compile; the rest loop back and wait on
the new completion event.

Also:
- Add BuildPCH diagnostic error messages to worker logs
- Update hello_world/main.cpp to include <iostream> (realistic test)
- Fix hardcoded line numbers in test_server.py and test_file_operation.py
- Add test_rapid_edits_with_hover: 50 rapid edits + hover each time
- Move publish_diagnostics after finish_compile to unblock waiters faster

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Launch compile as a detached task (loop.schedule) so LSP $/cancelRequest
  cannot kill in-flight compilations and leave doc.compiling stuck forever
- Add RAII CompileGuard to ensure doc.compiling is always cleaned up
- Drop stale feature requests when ast_dirty after ensure_compiled
- Add is_preamble_complete() to defer PCH rebuilds during incomplete edits
- Add #include and import completion intercepted at master level
- Log BuildPCH diagnostic errors for debuggability

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Rename edit.jsonl → rapid_edit.jsonl and add to repo
- Remove unused kWorkerRequestTimeout constant
- Document why timeout is disabled (eventide spurious cancellation bug)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace #include <cstdio> with #include "common.h" in
test_preamble_edit_then_hover to avoid slow PCH rebuilds on macOS CI
that cause SIGPIPE timeouts.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… test

- Add word boundary check in detect_completion_context so identifiers
  like "important" are not mistaken for "import" keyword
- Make negative-path include completion test assert non-null result

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
LSP clients may close the pipe at any time (editor exit, test teardown).
Without this, writing to the closed pipe kills the server with signal 13
instead of returning EPIPE. Guarded with #ifndef _WIN32 for portability.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@16bit-ykiko 16bit-ykiko changed the title feat: smart PCH rebuild, #include/import completion, buffer-aware module deps feat: smart PCH rebuild, #include/import completion, rapid-edit robustness Apr 6, 2026
@16bit-ykiko
16bit-ykiko merged commit e239b0d into main Apr 6, 2026
14 checks passed
@16bit-ykiko
16bit-ykiko deleted the feat/smart-pch-rebuild branch April 6, 2026 06:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant